/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package genomemap.cef.pui.pob;

import cef.pui.pob.*;
import commons.core.Generator;
import commons.core.LikelihoodComputer;
import commons.core.ModelEstimator;
import commons.core.Simulator;
import commons.util.PropertyUtil;
import genomemap.cef.event.DrawContigMap_Evt;
import genomemap.data.AssignmentData;
import genomemap.data.KSA00Data;
import genomemap.data.OrganismData;
import genomemap.data.TAB08Data;
import genomemap.map.GeneticMapFunction;
import genomemap.model.KSA00;
import genomemap.model.TAB08;
import genomemap.provider.Providers;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Properties;

import static commons.core.ValueTypes.StringList;

/**
 * Builds various value objects in coalescent-core using string based key-value pairs. The key-value
 * pairs are provided via a {@link Properties} object.
 *
 * @author Susanta Tewari
 * @history Created on Mar 18, 2012.
 */
public class Builders_Gen {

    /**
     * Builder for value type {@code AssignmentData}. The available properties are: <ul> <li>{@code
     * genomemap.builder.AssignmentData.url = assignmentdata:csv//URL }</li> </ul>
     *
     *
     * @param props properties object passed from event implementations
     * @return a new builder instance for {@code AssignmentData}
     */
    public static Builder<AssignmentData> of_AssignmentData_File(final Properties props,
            String prefix) {

        if (prefix == null) prefix = "genomemap.builder.AssignmentData";

        return new URLBasedBuilder<AssignmentData>(prefix, props) {

            @Override
            protected Class<genomemap.provider.Providers
                .AssignmentDataProviderFileBased> getDefaultProviderClass() {
                return genomemap.provider.Providers.AssignmentDataProviderFileBased.class;
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        };
    }

    /**
     * Builder for value type {@code KSA00Data}. The available properties are:
     * <ul>
     *     <li>{@code genomemap.builder.KSA00Data.url = ksa00data:xml//URL }</li>
     * </ul>
     *
     *
     * @param props properties object passed from event implementations
     * @param prefix
     * @return a new builder instance for {@code KSA00Data}
     */
    public static Builder<KSA00Data> of_Data_KSA00_File(final Properties props, String prefix) {

        if (prefix == null) prefix = "genomemap.builder.KSA00Data";

        return new URLBasedBuilder<KSA00Data>(prefix, props) {

            @Override
            protected Class<Providers.KSA00DataProviderFileBased> getDefaultProviderClass() {
                return Providers.KSA00DataProviderFileBased.class;
            }
            @Override
            public String getBuilderString() {
                return "genomemap.cef.pui.pob.Builders_Gen$Data_KSA00_File";
            }
        };
    }

    /**
     * Builder for value type {@code TAB08Data}. The available properties are:
     * <ul>
     *     <li>{@code genomemap.builder.TAB08Data.url = tab08data:xml//URL }</li>
     * </ul>
     *
     *
     * @param props properties object passed from event implementations
     * @param prefix
     * @return a new builder instance for {@code TAB08Data}
     */
    public static Builder<TAB08Data> of_Data_TAB08_File(final Properties props, String prefix) {

        if (prefix == null) prefix = "genomemap.builder.TAB08Data";

        return new URLBasedBuilder<TAB08Data>(prefix, props) {

            @Override
            protected Class<Providers.TAB08DataProviderFileBased> getDefaultProviderClass() {
                return Providers.TAB08DataProviderFileBased.class;
            }
            @Override
            public String getBuilderString() {
                return "genomemap.cef.pui.pob.Builders_Gen$Data_TAB08_File";
            }
        };
    }

    /**
     * Builder for value type {@code OrganismData}. The available properties are:
     * <ul>
     *     <li>{@code genomemap.builder.OrganismData.linkage-groups = comma separated linkage groups}</li>
     *     <li>{@code genomemap.builder.OrganismData.url = organismdata:files//URL }</li>
     * </ul>
     *
     *
     * @param props properties object passed from event implementations
     * @param prefix
     * @return a new builder instance for {@code OrganismData}
     */
    public static OrganismDataBuilder of_Data_OrganismData_Dir(final Properties props,
            String prefix) {

        if (prefix == null) prefix = "genomemap.builder.OrganismData";

        return new OrganismDataBuilder(prefix, props);
    }

    /**
     * Builder for value type {@code ModelEstimator<KSA00, KSA00Data, KSA00Data, ?>}. The available
     * properties are: <ul> <li>{@code genomemap.builder.KSA00Data.url = ksa00data:xml//URL }<a
     * href="genomemap/cef/pui/pob/doc-files/ksa00-data.xml.txt">file format</a>, must accompany the
     * <a href="genomemap/cef/pui/pob/doc-files/KSA00Data.xsd.txt">schema</a></li> <li>{@code
     * genomemap.builder.KSA00Estimator.implCode = ksa00estimator:conj-gradient}</li> </ul>
     *
     *
     * @param props properties object passed from event implementations
     * @param prefix
     * @return a new builder instance for {@code ModelEstimator<KSA00, KSA00Data, KSA00Data, ?>}
     */
    public static Builder<ModelEstimator<KSA00, KSA00Data, KSA00Data,
            ?>> of_ModelEstimator_KSA00(final Properties props, String prefix) {

        if (prefix == null) prefix = "genomemap.builder.KSA00Estimator";

        return new DataBasedBuilder<ModelEstimator<KSA00, KSA00Data, KSA00Data, ?>, KSA00,
                                    KSA00Data,
                                    genomemap.provider.Providers.KSA00EstimatorProvider>(prefix,
                                        props) {

            @Override
            protected Builder<KSA00Data> getDataBuilder() {
                return of_Data_KSA00_File(props, null);
            }
            @Override
            protected Class<genomemap.provider.Providers
                .KSA00EstimatorProvider> getDefaultProviderClass() {
                return genomemap.provider.Providers.KSA00EstimatorProvider.class;
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        };
    }

    /**
     * Builder for value type {@code ModelEstimator<TAB08, TAB08Data, TAB08Data, ?>}. The available
     * properties are: <ul> <li>{@code genomemap.builder.TAB08Data.url = tab08data:xml//URL }<a
     * href="genomemap/cef/pui/pob/doc-files/tab08-data.xml.txt">file format</a>, must accompany the
     * <a href="genomemap/cef/pui/pob/doc-files/TAB08Data.xsd.txt">schema</a></li> <li>{@code
     * genomemap.builder.TAB08Estimator.implCode = tab08:interval-mle}</li> </ul>
     *
     *
     * @param props properties object passed from event implementations
     * @param prefix
     * @return a new builder instance for {@code ModelEstimator<TAB08, TAB08Data, TAB08Data, ?>}
     */
    public static Builder<ModelEstimator<TAB08, TAB08Data, TAB08Data,
            ?>> of_ModelEstimator_TAB08(final Properties props, String prefix) {

        if (prefix == null) prefix = "genomemap.builder.TAB08Estimator";

        return new DataBasedBuilder<ModelEstimator<TAB08, TAB08Data, TAB08Data, ?>, TAB08,
                                    TAB08Data,
                                    genomemap.provider.Providers.TAB08EstimatorProvider>(prefix,
                                        props) {

            @Override
            protected Builder<TAB08Data> getDataBuilder() {
                return of_Data_TAB08_File(props, null);
            }
            @Override
            protected Class<genomemap.provider.Providers
                .TAB08EstimatorProvider> getDefaultProviderClass() {
                return genomemap.provider.Providers.TAB08EstimatorProvider.class;
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        };
    }

    /**
     * Builder for value type {@code LikelihoodComputer<KSA00Data>}. The available properties are:
     * <ul> <li>{@code genomemap.builder.KSA00Lhood.implCode = ksa00:1}</li> </ul>
     *
     *
     * @param props builder properties
     * @param prefix
     * @return a new builder instance for {@code LikelihoodComputer<KSA00Data>}
     */
    public static Builder<LikelihoodComputer<KSA00Data>> of_LHoodComputer_KSA00(
            final Properties props, String prefix) {

        if (prefix == null) prefix = "genomemap.builder.KSA00Lhood";

        return new ICBasedBuilder<LikelihoodComputer<KSA00Data>,
                                  Providers.KSA00LHoodProvider>(prefix, props) {

            @Override
            protected Class<Providers.KSA00LHoodProvider> getDefaultProviderClass() {
                return Providers.KSA00LHoodProvider.class;
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        };
    }

    /**
     * Builder for value type {@code LikelihoodComputer<TAB08Data>}. The available properties are:
     * <ul>
     *     <li>{@code genomemap.builder.TAB08Lhood.implCode = tab08:rla | tab08:sfa}</li>
     * </ul>
     *
     *
     * @param props builder properties
     * @param prefix
     * @return a new builder instance for {@code LikelihoodComputer<TAB08Data>}
     */
    public static Builder<LikelihoodComputer<TAB08Data>> of_LHoodComputer_TAB08(
            final Properties props, String prefix) {

        if (prefix == null) prefix = "genomemap.builder.TAB08Lhood";

        return new ICBasedBuilder<LikelihoodComputer<TAB08Data>,
                                  Providers.TAB08LHoodProvider>(prefix, props) {

            @Override
            protected Class<Providers.TAB08LHoodProvider> getDefaultProviderClass() {
                return Providers.TAB08LHoodProvider.class;
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        };
    }

    /**
     * Builder for value type {@code Simulator.DATA<KSA00, KSA00Data>}. The properties are:
     * <ul>
     *     <li>{@code genomemap.builder.KSA00DataSimulator.implCode = ksa00data:1}</li>
     * </ul>
     *
     *
     * @param props builder properties
     * @param prefix
     * @return a new builder instance for {@code Simulator.DATA<KSA00, KSA00Data>}
     */
    public static Builder<Simulator.DATA<KSA00,
            KSA00Data>> of_Simulator_Data_KSA00(final Properties props, String prefix) {

        if (prefix == null) prefix = "genomemap.builder.KSA00DataSimulator";

        return new ICBasedBuilder<Simulator.DATA<KSA00, KSA00Data>,
                                  Providers.KSA00DataSimulatorProvider>(prefix, props) {

            @Override
            protected Class<Providers.KSA00DataSimulatorProvider> getDefaultProviderClass() {
                return Providers.KSA00DataSimulatorProvider.class;
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        };
    }

    /**
     * Builder for value type {@code Simulator.DATA<TAB08, TAB08Data>}. The properties are:
     * <ul>
     *     <li>{@code genomemap.builder.TAB08DataSimulator.implCode = tab08data:1}</li>
     * </ul>
     *
     *
     * @param props builder properties
     * @param prefix
     * @return a new builder instance for {@code Simulator.DATA<TAB08, TAB08Data>}
     */
    public static Builder<Simulator.DATA<TAB08,
            TAB08Data>> of_Simulator_Data_TAB08(final Properties props, String prefix) {

        if (prefix == null) prefix = "genomemap.builder.TAB08DataSimulator";

        return new ICBasedBuilder<Simulator.DATA<TAB08, TAB08Data>,
                                  Providers.TAB08DataSimulatorProvider>(prefix, props) {

            @Override
            protected Class<Providers.TAB08DataSimulatorProvider> getDefaultProviderClass() {
                return Providers.TAB08DataSimulatorProvider.class;
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        };
    }

    /**
     * Builder for value type {@code Generator.MODEL<KSA00>}. The properties are:
     * <ul>
     *     <li>{@code genomemap.builder.KSA00ModelGenerator.implCode = ksa00:1}</li>
     * </ul>
     *
     *
     * @param props builder properties
     * @param prefix
     * @return a new builder instance for {@code Generator.MODEL<KSA00>}
     */
    public static Builder<Generator.MODEL<KSA00,
            KSA00>> of_Generator_Model_KSA00(final Properties props, String prefix) {

        if (prefix == null) prefix = "genomemap.builder.KSA00ModelGenerator";

        return new ICBasedBuilder<Generator.MODEL<KSA00, KSA00>,
                                  Providers.KSA00GeneratorProvider>(prefix, props) {

            @Override
            protected Class<Providers.KSA00GeneratorProvider> getDefaultProviderClass() {
                return Providers.KSA00GeneratorProvider.class;
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        };
    }

    /**
     * Builder for value type {@code Generator.MODEL<TAB08>}. The properties are:
     * <ul>
     *     <li>{@code genomemap.builder.TAB08ModelGenerator.implCode = tab08:1}</li>
     * </ul>
     *
     *
     * @param props builder properties
     * @param prefix
     * @return a new builder instance for {@code Generator.MODEL<TAB08>}
     */
    public static Builder<Generator.MODEL<TAB08,
            TAB08>> of_Generator_Model_TAB08(final Properties props, String prefix) {

        if (prefix == null) prefix = "genomemap.builder.TAB08ModelGenerator";

        return new ICBasedBuilder<Generator.MODEL<TAB08, TAB08>,
                                  Providers.TAB08GeneratorProvider>(prefix, props) {

            @Override
            protected Class<Providers.TAB08GeneratorProvider> getDefaultProviderClass() {
                return Providers.TAB08GeneratorProvider.class;
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        };
    }

    /**
     * Builder for interface {@code DrawContigMap_Evt.ContigMapType}. The available properties are:
     * <ul><li>{@code <li>{@code genomemap.ContigMapType.format = FULL | MINIMAL}</li></ul>
     *
     * @param props properties object containing builder properties
     * @return a new builder instance for {@code DrawContigMap_Evt.ContigMapType}
     */
    public static Builder<DrawContigMap_Evt.ContigMapType> of_ContigMapType(final Properties props,
            String prefix) {

        if (prefix == null) prefix = "genomemap.ContigMapType";

        return new StringBasedBuilder<DrawContigMap_Evt.ContigMapType>(prefix, props, "format") {

            @Override
            protected DrawContigMap_Evt.ContigMapType newInstance(final String propValue) {
                return DrawContigMap_Evt.ContigMapType.valueOf(propValue);
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        };
    }

    /**
     * Properties:
     * <ul>
     *     <li>{@code genomemap.builder.GeneticMapFunctions.implCode = haldane,kosambi [, separated impl-codes]}</li>
     * </ul>
     *
     *
     * @param props builder properties
     * @return a new builder instance for {@code LikelihoodComputer<TAB08Data>}
     */
    public static Builder<Collection<GeneticMapFunction>> of_GeneticMapFunctionS(
            final Properties props, String prefix) {

        if (prefix == null) prefix = "genomemap.builder.GeneticMapFunctions";

        final String key      = "genomemap.builder.GeneticMapFunctions.implCode";
        final String property = props.getProperty(key);

        if ((property == null) || property.isEmpty()) {
            throw new BuilderException("missing/invalid key: " + key);
        }

        final String[] impl_codes = property.split(",");
        final String myPrefix     = prefix;

        final class GMFunctionBuilder
                extends ICBasedBuilder<GeneticMapFunction, Providers.GeneticMapFunctionProvider> {

            GMFunctionBuilder(final Properties props) {
                super(myPrefix, props);
            }
            @Override
            protected Class<Providers.GeneticMapFunctionProvider> getDefaultProviderClass() {
                return Providers.GeneticMapFunctionProvider.class;
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        }

        final Properties props_temp = PropertyUtil.copyProperties(props);

        return new Builder<Collection<GeneticMapFunction>>(prefix, props) {

            @Override
            protected Collection<GeneticMapFunction> buildFromProps() throws BuilderException {

                final Collection<GeneticMapFunction> result = new ArrayList<>();

                for (final String impl_code : impl_codes) {

                    props_temp.setProperty(key, impl_code);
                    result.add(new GMFunctionBuilder(props_temp).build());
                }

                return result;
            }
            @Override
            public String getBuilderString() {
                return "NotYetImplemented";
            }
        };
    }

    /**
     * Builder with same properties as {@link #of_Data_KSA00_File(java.util.Properties, String)}.
     */
    public static final class Data_KSA00_File extends Builder.Delegate<KSA00Data> {

        public Data_KSA00_File(final String prefix, final Properties props) {

            super(of_Data_KSA00_File(props, null));

            setPrefix(prefix);
        }
    }

    /**
     * Builder with same properties as {@link #of_Data_TAB08_File(java.util.Properties, String)}.
     */
    public static final class Data_TAB08_File extends Builder.Delegate<TAB08Data> {

        public Data_TAB08_File(final String prefix, final Properties props) {

            super(of_Data_TAB08_File(props, null));

            setPrefix(prefix);
        }
    }

    /**
     * Properties:
     * <ul>
     *  <li>{@code genomemap.builder.TAB08Data.linkage-group = linkage groups(comma separated, if > 1) }</li>
     *  <li>{@code genomemap.builder.TAB08Data.url = organismdata:files//URL }</li>
     * </ul>
     */
    public static final class Data_TAB08_OrganismData extends Builder<TAB08Data> {

        private final String prefix;
        private final Properties props;

        public Data_TAB08_OrganismData(final String prefix, final Properties props) {

            super(prefix, props);

            this.prefix = prefix;
            this.props  = props;
        }

        @Override
        protected TAB08Data buildFromProps() throws BuilderException {

            final String linkagegroup             = "linkage-group";
            final int linkageGroup = cef.pui.pob.Builders.of_Integer(this.props, linkagegroup,
                                         prefix).build();
            final OrganismDataBuilder dataBuilder = new OrganismDataBuilder(prefix, this.props);

            dataBuilder.setPropertyLinkageGroups(linkagegroup);

            final OrganismData data = dataBuilder.build();

            return data.createTAB08Data(linkageGroup, data.genes(linkageGroup));
        }

        @Override
        public String getBuilderString() {
            return "genomemap.cef.pui.pob.Builders_Gen$Data_TAB08_OrganismData";
        }
    }

    /**
     * Properties:
     * <ul>
     *  <li>{@code genomemap.builder.StringList-Gene.OrganismData.title = list title</li>
     *  <li>{@code genomemap.builder.StringList-Gene.OrganismData.linkage-group = linkage groups(comma separated, if > 1) }</li>
     *  <li>{@code genomemap.builder.StringList-Gene.OrganismData.url = organismdata:files//URL }</li>
     * </ul>
     */
    public static final class StringList_Gene_OrganismData extends Builder<StringList> {

        private final String prefix;
        private final Properties props;

        /**
         * Constructs ...
         *
         *
         * @param props
         */
        public StringList_Gene_OrganismData(final String prefix, final Properties props) {

            super(prefix, props);

            this.prefix = prefix;
            this.props  = props;
        }

        @Override
        protected StringList buildFromProps() throws BuilderException {

            final String linkagegroup             = "linkage-group";
            final int linkageGroup = cef.pui.pob.Builders.of_Integer(this.props, linkagegroup,
                                         prefix).build();
            final OrganismDataBuilder dataBuilder = new OrganismDataBuilder(prefix, this.props);

            dataBuilder.setPropertyLinkageGroups(linkagegroup);

            final OrganismData data     = dataBuilder.build();
            final StringList stringList = new StringList(data.genes(linkageGroup));

            stringList.setTitle(getProperty(getFullPropertyKey("title")));

            return stringList;
        }

        @Override
        public String getBuilderString() {
            return "genomemap.cef.pui.pob.Builders_Gen$StringList_Gene_OrganismData";
        }
    }

    /**
     * Properties:
     * <ul>
     *  <li>{@code genomemap.builder.StringList-Probe.OrganismData.linkage-group = linkage groups(comma separated, if > 1) }</li>
     *  <li>{@code genomemap.builder.StringList-Probe.OrganismData.url = organismdata:files//URL }</li>
     * </ul>
     */
    public static final class StringList_Probe_OrganismData extends Builder<StringList> {

        private final String prefix;
        private final Properties props;

        public StringList_Probe_OrganismData(final String prefix, final Properties props) {

            super(prefix, props);

            this.prefix = prefix;
            this.props  = props;
        }

        @Override
        protected StringList buildFromProps() throws BuilderException {

            final String linkagegroup             = "linkage-group";
            final int linkageGroup = cef.pui.pob.Builders.of_Integer(this.props, linkagegroup,
                                         prefix).build();
            final OrganismDataBuilder dataBuilder = new OrganismDataBuilder(prefix, this.props);

            dataBuilder.setPropertyLinkageGroups(linkagegroup);

            final OrganismData data = dataBuilder.build();

            return new StringList(data.probes(linkageGroup));
        }

        @Override
        public String getBuilderString() {
            return "genomemap.cef.pui.pob.Builders_Gen$StringList_Probe_OrganismData";
        }
    }

    /**
     * Builder for value type {@code KSA00Data}. The available properties are: <ul> <li>{@code
     * genomemap.builder.KSA00Data.linkage-group = one of the valid linkage groups}</li> <li>{@code
     * genomemap.builder.KSA00Data.url = organismdata:files//URL }</li> </ul>
     */
    public static final class Data_KSA00_OrganismData extends Builder<KSA00Data> {

        private final String prefix;
        private final Properties props;

        public Data_KSA00_OrganismData(final String prefix, final Properties props) {

            super(prefix, props);

            this.prefix = prefix;
            this.props  = props;
        }

        @Override
        protected KSA00Data buildFromProps() throws BuilderException {

            final String linkagegroup             = "linkage-group";
            final int linkageGroup = cef.pui.pob.Builders.of_Integer(this.props, linkagegroup,
                                         prefix).build();
            final OrganismDataBuilder dataBuilder = new OrganismDataBuilder(prefix, this.props);

            dataBuilder.setPropertyLinkageGroups(linkagegroup);

            final OrganismData data = dataBuilder.build();

            return data.createKSA00Data(linkageGroup, data.probes(linkageGroup));
        }

        @Override
        public String getBuilderString() {
            return "genomemap.cef.pui.pob.Builders_Gen$Data_KSA00_OrganismData";
        }
    }

    /**
     * Builder with same properties as {@link #of_LHoodComputer_KSA00(java.util.Properties, String)}.
     */
    public static final class LHoodComputer_KSA00
            extends Builder.Delegate<LikelihoodComputer<KSA00Data>> {

        public LHoodComputer_KSA00(final String prefix, final Properties props) {

            super(of_LHoodComputer_KSA00(props, null));

            setPrefix(prefix);
        }
    }

    /**
     * Builder with same properties as {@link #of_LHoodComputer_TAB08(java.util.Properties, String)}.
     */
    public static final class LHoodComputer_TAB08
            extends Builder.Delegate<LikelihoodComputer<TAB08Data>> {

        public LHoodComputer_TAB08(final String prefix, final Properties props) {

            super(of_LHoodComputer_TAB08(props, null));

            setPrefix(prefix);
        }
    }

    private Builders_Gen() {}
}
